/********************************************************************************
* @file    queue.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-10-10
* @brief   消息队列 借鉴nrf
* @example 
#define RECV_Q_ITEM_CNT                             (8)
#define RECV_Q_ITEM_SIZE                            (20)
// 消息队列总缓存区
static uint8_t m_recv_q_buff[RECV_Q_ITEM_CNT * RECV_Q_ITEM_SIZE] = {0};
// 定义队列消息结构体
queue_t m_recv_q =
{
    .pbuff     = m_recv_q_buff,
    .front     = 0,
    .rear      = 0,
    .item_cnt  = RECV_Q_ITEM_CNT,
    .item_size = RECV_Q_ITEM_SIZE
};
// 消息队列项目临时缓存区
uint8_t g_recv_data[USB_RECV_Q_ITEM_SIZE] = {0};

// 数据入队(data长度为RECV_Q_ITEM_SIZE)
queue_en(&m_recv_q, data);

// 数据出队(如果队列为空，则返回)
if (!queue_de(&m_recv_q, g_recv_data))
    return;
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

/* Private Includes ----------------------------------------------------------*/
#include "queue.h"

/* Private Function Prototypes -----------------------------------------------*/
/**
 * @brief  [消息队列] 初始化
 * @param  q: 队列信息指针
 * @param  data: 队列缓存区
 * @param  item_cnt: 队列总数量
 * @param  item_size: 队列总大小
 * @retval 1--成功 0--失败
 */
bool queue_init(queue_t *q, uint8_t *data, uint32_t item_cnt, uint32_t item_size)
{
    q->pbuff     = data;
    q->item_cnt  = item_cnt;
    q->item_size = item_size;
    q->front     = 0;
    q->rear      = 0;
    return true;
}

/**
 * @brief  [消息队列] 入队
 * @param  q: 队列信息指针
 * @param  data: 数据头指针
 * @retval 1--成功 0--失败
 */
bool queue_en(queue_t *q, uint8_t *data, uint16_t len)
{
    if (((q->rear + 1) % q->item_cnt) == q->front)
        return false;
    memset(q->pbuff + (q->rear * q->item_size),0, q->item_size);
    memcpy(q->pbuff + (q->rear * q->item_size), data, len);
    q->rear = (q->rear + 1) % q->item_cnt;
    return true;
}

/**
 * @brief  [消息队列] 出队
 * @param  q: 队列信息指针
 * @param  data: 得到当前队列信息数据头指针
 * @retval 1--成功 0--失败
 */
bool queue_de(queue_t *q, uint8_t *data)
{
    if (q->front == q->rear)
        return false;

    if (data)
    {
        memcpy(data, q->pbuff + (q->front * q->item_size), q->item_size);
    }
    q->front = (q->front + 1) % q->item_cnt;
    return true;
}

/**
 * @brief  [消息队列] 队列是否为空
 * @param  q: 队列信息指针
 * @retval 1--空 0--非空
 */
bool queue_is_null(queue_t *q)
{
    if (q->front == q->rear)
        return true;
    return false;
}

/**
 * @brief  [消息队列] 读取当前第一个队列信息
 * @param  q: 队列信息指针
 * @retval 第一个队列信息头指针
 */
uint8_t* queue_read(queue_t *q)
{
    if (q->front == q->rear)
        return NULL;

    return q->pbuff + (q->front * q->item_size);
}

/**
 * @brief  [消息队列] 读取队列成员数
 * @param  q: 队列信息指针
 * @retval 队列剩余空间
 */
uint32_t queue_get_space(queue_t *q)
{
    if (q->front > q->rear)
    {
        return q->front - q->rear;
    }
    else
    {
        return (q->item_cnt - q->rear) + q->front;
    }
}
